from flask import Flask, request, jsonify
import json

app = Flask(__name__)

# 注册支持的 RPC 方法到字典
rpc_methods = {}

def register_rpc(method_name):
    """装饰器：注册一个 RPC 方法"""
    def decorator(func):
        rpc_methods[method_name] = func
        return func
    return decorator

@app.route('/rpc', methods=['POST'])
def rpc_handler():
    """处理 JSON-RPC 请求"""
    data = request.get_json()
    
    # 验证请求格式
    if not data or data.get('jsonrpc') != '2.0':
        return jsonify({
            'jsonrpc': '2.0',
            'id': None,
            'error': {
                'code': -32600,
                'message': 'Invalid Request'
            }
        }), 400

    method = data.get('method')
    params = data.get('params', [])
    _id = data.get('id')

    # 调用对应方法
    if method in rpc_methods:
        try:
            # 根据参数类型确定调用方式：数组参数 vs 对象参数
            if isinstance(params, list):
                result = rpc_methods[method](*params)
            elif isinstance(params, dict):
                result = rpc_methods[method](**params)
            else:
                raise TypeError("Parameters must be list or object")
            
            return jsonify({
                'jsonrpc': '2.0',
                'id': _id,
                'result': result
            })
        except Exception as e:
            return jsonify({
                'jsonrpc': '2.0',
                'id': _id,
                'error': {
                    'code': -32603,
                    'message': 'Internal error',
                    'data': str(e)
                }
            }), 500
    else:
        return jsonify({
            'jsonrpc': '2.0',
            'id': _id,
            'error': {
                'code': -32601,
                'message': 'Method not found'
            }
        }), 404

# 注册示例 RPC 方法

@register_rpc('add')
def add(a: int, b: int):
    """两个数相加"""
    return a + b

@register_rpc('subtract')
def subtract(minuend: int, subtrahend: int):
    """两个数相减"""
    return minuend - subtrahahend  # 故意写错拼写，演示错误处理

if __name__ == '__main__':
    app.run(port=5000)